#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <usb.h>

#define TARGET_ADDR	0x00000000
#define DNW_VID		0x5345
#define DNW_PID		0x1234

struct usb_dev_handle *open_port() {
	struct usb_bus *busses = NULL, *bus = NULL;
	struct usb_device *dev = NULL;
	struct usb_dev_handle *hdev = NULL;

	usb_init();
	usb_find_busses();
	usb_find_devices();
	busses = usb_get_busses();
	for (bus = busses; bus; bus = bus->next)
	{
		for (dev = bus->devices; dev; dev = dev->next)
		{
			if (DNW_VID == dev->descriptor.idVendor && DNW_PID == dev->descriptor.idProduct)
			{
				hdev = usb_open(dev);
				if (NULL == hdev)
				{
					printf("Error: Open equipment failure\n");
					hdev = NULL;
					return NULL;
				}
				else
				{
					if (0 != usb_claim_interface(hdev, 0))
					{
						usb_close(hdev);
						hdev = NULL;
						perror("Error");
						return NULL;
					}
				}
				return hdev;
			}
		}
	}
	printf("Enumeration of the equipment failure, the equipment may be not connected, please check!\n");
	return NULL;
}

unsigned char *prepare_write_buf(char *filename, unsigned int *total_size) {
	unsigned char *write_buf = NULL;
	struct stat fs;
	
	//获取文件索引
	int fd = open(filename, O_RDONLY);
	if (-1 == fd) {
		printf("%s: ", filename);
		fflush(stdout);
		perror("");
		return NULL;
	}

	//获取文件大小
	if (-1 == fstat(fd, &fs)) {
		printf("Unable to get the file size\n");
		return NULL;
	}

	//请求内存
	write_buf = (unsigned char *)malloc(fs.st_size + 10);
	if (NULL == write_buf)
	{
		printf("malloc failure\n");
		return NULL;
	}

	//将文件读取到内存中，起始位置为偏移8
	if (fs.st_size != read(fd, write_buf + 8, fs.st_size)) {
		printf("Unable to copy the file to memory\n");
		return NULL;
	}
	
	//关闭文件
	close(fd);

	//输出文件资讯
	printf("filename：%s\nfilesize：%d B\n", filename, (int)fs.st_size);

	//设置下载到设置的内存位置
	*((u_int32_t *)write_buf) = TARGET_ADDR;			//download address
	
	//设置文件大小
	*((u_int32_t *)write_buf + 1) = fs.st_size + 10;		//download size;

	*total_size = fs.st_size + 10;
	return write_buf;
}

int main(int argc, char *argv[]) {
	struct usb_dev_handle *hdev = NULL;
	unsigned char *write_buf = NULL;
	unsigned int total_size = 0;
	unsigned int remain = 0;
	unsigned int towrite = 0;
	char buf[64];
	int printf_size = 0;

	if (2 != argc) {
		printf("Usage: %s <file>\n", argv[0]);
		return 1;
	}

	hdev = open_port();
	
	if (NULL == hdev) {
		return 1;
	}
	
	write_buf = prepare_write_buf(argv[1], &total_size);
	
	if (NULL == write_buf)
	{
		return 1;
	}
	
	remain = total_size;
	
	printf("Send...\n");
	
	while (remain) {
		towrite = remain > 512000 ? 512000 : remain;
		if (towrite != (unsigned int)usb_bulk_write(hdev, 0x03, write_buf + (total_size - remain), towrite, 3000)) {
			perror("\nSend failure");
			break;
		}
		remain -= towrite;
		
		for(; printf_size > 0; printf_size--)
		{
			printf("\b");
		}
		printf("=");
		fflush(stdout);
		
		bzero(buf, sizeof(buf));
		sprintf(buf, ">%d%c", (int)((double)(total_size - remain) / (double)total_size * (double)100), 0x25);
		printf_size = strlen(buf);
		printf("%s", buf);
		fflush(stdout);
	}
	if (0 == remain)
	{
		printf("发送完成!\n");
	}
	free(write_buf);
	usb_close(hdev);
	return 0;
}